﻿using SharpGL.SceneGraph.Assets;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Management.Instrumentation;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media.Media3D;
using static System.Net.WebRequestMethods;
using static System.Windows.Forms.AxHost;

namespace AutoStar.Common
{
    public interface SliceStrategy
    {
        List<Line3D>[] LayerSlicing(Model3D model, float maxHeight, float minHeight);
        List<Line3D>[] LayerSlicing1(Model3D model, float maxHeight, float minHeight);
    }

    public class IsothickSliceStrategy : SliceStrategy
    {
        public List<Line3D>[] LayerSlicing(Model3D model, float maxHeight, float minHeight)
        {
            Triangle3D[] triangles = model.triangles.ToArray();
            float[] layersHeights = new float[(int)((model.modelHeight + model.moveZ) / maxHeight) + 1];
            for (int i = 0; i < layersHeights.Length; i++)
            {
                layersHeights[i] = minHeight + i * maxHeight;
            }
            List<Line3D>[] layers = new List<Line3D>[layersHeights.Length];
            for (int i = 0; i < layers.Length; i++)
            {
                layers[i] = new List<Line3D>();
            }
            for (int i = 0; i < triangles.Length; i++)
            {
                Utilities.getTriangleIntersectionLines(triangles[i], layersHeights, layers);
            }
            return layers;
        }
        public List<Line3D>[] LayerSlicing1(Model3D model, float maxHeight, float minHeight)
        {
            Triangle3D[] triangles = model.triangles.ToArray();
            // 计算模型在Y轴方向上的最大和最小Y值
            float minY = float.MaxValue;
            float maxY = float.MinValue;
            foreach (var triangle in triangles)
            {
                minY = Math.Min(minY, Math.Min(triangle.p1.Y, Math.Min(triangle.p2.Y, triangle.p3.Y)));
                maxY = Math.Max(maxY, Math.Max(triangle.p1.Y, Math.Max(triangle.p2.Y, triangle.p3.Y)));
            }
            // 根据层高参数计算切片层数
            int layerCount = (int)((maxY - minY) / maxHeight) + 1;
            float[] layersHeights = new float[layerCount];
            for (int i = 0; i < layerCount; i++)
            {
                layersHeights[i] = minY + i * maxHeight;
            }
            List<Line3D>[] layers = new List<Line3D>[layerCount];
            for (int i = 0; i < layers.Length; i++)
            {
                layers[i] = new List<Line3D>();
            }
            for (int i = 0; i < triangles.Length; i++)
            {
                Utilities.GetTriangleIntersectionLinesY(triangles[i], layersHeights, layers, minY, maxHeight);
            }
            return layers;
        }
    }

    public class AdaptiveSliceStrategy : SliceStrategy
    {
        public List<Line3D>[] LayerSlicing(Model3D model, float maxHeight, float minHeight)
        {
            Triangle3D[] triangles = model.triangles.ToArray();
            //float[] layersHeights = new float[(int)(model.modelHeight / maxHeight) + 1];
            float[] layersHeights = new float[(int)(model.modelHeight / maxHeight)];
            for (int i = 0; i < layersHeights.Length; i++)
            {
                layersHeights[i] = minHeight + i * maxHeight;
            }
            for (int i = 0; i < triangles.Length; i++)
            {
                float[] result = Utilities.ModifyLayerHeight(triangles[i], layersHeights, maxHeight, minHeight, 0.1f);
                if (result.Length > 0) layersHeights = result;
            }
            List<Line3D>[] layers = new List<Line3D>[layersHeights.Length];
            for (int i = 0; i < layers.Length; i++)
            {
                layers[i] = new List<Line3D>();
            }
            for (int i = 0; i < triangles.Length; i++)
            {
                Utilities.getTriangleIntersectionLines(triangles[i], layersHeights, layers);
            }
            return layers;
        }

        public List<Line3D>[] LayerSlicing1(Model3D model, float maxHeight, float minHeight)
        {
            throw new NotImplementedException();
        }
    }

    public class SliceContext
    {
        private SliceStrategy strategy;

        public SliceContext(SliceStrategy strategy)
        {
            this.strategy = strategy;
        }

        public List<Line3D>[] executeStrategy(Model3D model, float maxHeight, float minHeight)
        {
            return strategy.LayerSlicing(model, maxHeight, minHeight);
        }
        public List<Line3D>[] executeStrategy1(Model3D model, float maxHeight, float minHeight)
        {
            return strategy.LayerSlicing1(model, maxHeight, minHeight);
        }

    }

    public interface FillStrategy
    {
        /// <summary>
        /// 横切填充
        /// </summary>
        /// <returns></returns>
        List<Point3D> PathFilling(List<Line3D> layer, float fillInterval, int mode);
        /// <summary>
        /// 竖切填充
        /// </summary>
        /// <returns></returns>
        List<Point3D> PathFilling(List<Line3D> layer, float fillInterval);
    }


    public class SimpleFillStrategy : FillStrategy
    {
        #region 导出多边形/路径列表为txt
        /// <summary>
        /// 多边形路径列表,导出txt
        /// </summary>
        /// <param name="polygons"></param>
        /// <param name="filePath"></param>
        public static void ExportPolygonsToTxt(List<Polygon3D> polygons, string filePath)
        {
            using (StreamWriter writer = new StreamWriter(filePath, true))
            {
                writer.WriteLine("多边形顶点列表：");
                for (int i = 0; i < polygons.Count; i++)
                {
                    writer.WriteLine($"多边形 {i + 1}：");
                    foreach (Point3D point in polygons[i].points)
                    {
                        writer.WriteLine($"{point.X}, {point.Y}, {point.Z}");
                    }
                    writer.WriteLine(); // 空行分隔每个多边形
                }
            }
            Console.WriteLine($"多边形顶点已导出到：{filePath}");
        }
        /// <summary>
        /// 填充路径导出txt
        /// </summary>
        /// <param name="lines"></param>
        /// <param name="filePath"></param>
        public static void ExportFillPathsToTxt(List<Line3D> lines, string filePath)
        {
            using (StreamWriter writer = new StreamWriter(filePath, true))
            {
                writer.WriteLine("");
                for (int i = 0; i < lines.Count; i++)
                {
                    writer.WriteLine($"{lines[i].start.X},{lines[i].start.Y},{"*"},{lines[i].end.X},{lines[i].end.Y}");
                }
            }
            Console.WriteLine($"多边形顶点已导出到：{filePath}");
        }
        #endregion
        public List<Point3D> PathFilling(List<Line3D> lines, float fillInterval, int mode)
        {
            List<Point3D> points = new List<Point3D>();
            if (lines.Count == 0) return points;

            // 获取所有多边形
            List<Polygon3D> polygons = Utilities.LinesToPolygons(lines);
            // 执行增强填充
            List<Line3D> fillPaths = new List<Line3D>();
            foreach (Polygon3D polygon in polygons)
            {
                fillPaths.AddRange(Utilities.RobustFill(polygon, 0.2f, 0));
                //如果fillPaths为null 跳出
                if (fillPaths == null || fillPaths.Count == 0)
                    continue;
                // 验证结果
                ExportFillPathsToTxt(fillPaths, @"C:\Users\AKR\Desktop\新建文件夹\fillPaths.txt");
                List<Line3D> line3Ds = fillPaths;
                Point3D start1 = line3Ds.First().start;
                Global.StopPrintPoints.Add(start1);
                foreach (Line3D line3D in line3Ds)
                {
                    Point3D start = line3D.start;
                    points.Add(start);
                    Point3D end = line3D.end;
                    end.mode = 1; // 设置从start到end是移动中打印模式
                    points.Add(end);
                }
                Point3D end1 = line3Ds.Last().end;
                Global.StopPrintPoints.Add(end1);
            }
            // 生成打印路径
            //List<Point3D> printPoints = PathFilling(fillPaths, 0.2f, 0);
            return points;
        }
        private static int currentMode = 0; // 初始模式设置为0

        public List<Point3D> PathFilling(List<Line3D> lines, float fillInterval)
        {
            List<Point3D> points = new List<Point3D>();
            if (lines.Count == 0) return points;

            // 获取所有多边形
            List<Polygon3D> polygons = new List<Polygon3D>();
            if (Global.SliceParaVM.SliceModeSelectedIndex == 0)
                polygons = Utilities.LinesToPolygons(lines);
            else
                polygons = Utilities.LinesToPolygons1(lines);
            foreach (Polygon3D polygon in polygons)
            {
                // 获取填充路径
                int modeForThisPolygon = currentMode; // 获取当前模式
                List<Line3D> line3Ds = Utilities.FillPolygon(polygon, fillInterval, modeForThisPolygon);

                if (line3Ds.Count == 0) continue;
                Point3D start1 = line3Ds.First().start;
                Global.StopPrintPoints.Add(start1);
                foreach (Line3D line3D in line3Ds)
                {
                    Point3D start = line3D.start;
                    points.Add(start);
                    Point3D end = line3D.end;
                    end.mode = 1; // 设置从start到end是移动中打印模式
                    points.Add(end);
                }
                Point3D end1 = line3Ds.Last().end;
                Global.StopPrintPoints.Add(end1);

                // 切换打印模式
                currentMode = currentMode == 0 ? 1 : 0;
            }
            return points;
        }
        //List<Point3D> FillStrategy.PathFilling(List<Line3D> layer, float fillInterval, int mode)
        //{
        //    throw new NotImplementedException();
        //}
    }
    public class ComplexFillStrategy : FillStrategy
    {
        public List<Point3D> PathFilling(List<Line3D> layer, float fillInterval, int mode)
        {
            List<Point3D> points = new List<Point3D>();
            List<Polygon3D> polygons = Utilities.LinesToPolygons(layer);//根据层数据获得多边形
            //凹多边形凸分解
            List<Polygon3D> afterCut = new List<Polygon3D>();
            foreach (Polygon3D polygon in polygons)
            {
                double d = 0;//判断多边形是否为顺时针
                for (int j = 0; j < polygon.points.Count - 1; j++)
                {
                    d += -0.5 * (polygon.points[j + 1].Y + polygon.points[j].Y) * (polygon.points[j + 1].X - polygon.points[j].X);
                }
                if (d < 0) polygon.points.Reverse();
                List<Polygon3D> temp = Utilities.CutPolygon(polygon);
                foreach (Polygon3D poly in temp)
                {
                    afterCut.Add(poly);
                }
            }
            polygons = afterCut;
            //轮廓偏置
            foreach (Polygon3D polygon in polygons)
            {
                List<Polygon3D> afterOffset = new List<Polygon3D>();
                List<Polygon3D> temp = Utilities.OffsetPolygon(polygon, fillInterval, 2);//对轮廓进行偏置
                foreach (Polygon3D poly in temp)
                {
                    afterOffset.Add(poly);
                }
                //形成打印路径
                for (int j = 0; j < afterOffset.Count - 1; j++)
                {
                    List<Point3D> point3Ds = afterOffset[j].points;
                    for (int k = 0; k < point3Ds.Count; k++)
                    {
                        Point3D tempPoi = new Point3D(point3Ds[k].X, point3Ds[k].Y, point3Ds[k].Z, 1);
                        if (k == 0) tempPoi.mode = 0;
                        points.Add(tempPoi);
                    }
                }
                //对最后一个轮廓进行填充
                List<Line3D> line3DTemp = Utilities.FillPolygon(afterOffset[afterOffset.Count - 1], fillInterval, mode);
                foreach (Line3D line in line3DTemp)
                {
                    Point3D tempSta = new Point3D(line.start.X, line.start.Y, line.start.Z, 0);
                    Point3D tempEnd = new Point3D(line.end.X, line.end.Y, line.end.Z, 1);
                    points.Add(tempSta);
                    points.Add(tempEnd);
                }
            }
            return points;
        }

        public List<Point3D> PathFilling(Polygon3D polygon3D, float fillInterval, int mode)
        {
            throw new NotImplementedException();
        }

        public List<Point3D> PathFilling(List<Line3D> layer, float fillInterval)
        {
            throw new NotImplementedException();
        }
    }

    public class FillContext
    {
        private FillStrategy strategy;

        public FillContext(FillStrategy strategy)
        {
            this.strategy = strategy;
        }

        public List<Point3D> executeStrategy(List<Line3D> layer, float fillInterval, int mode)
        {
            return strategy.PathFilling(layer, fillInterval, mode);
        }
        public List<Point3D> executeStrategy(List<Line3D> layer, float fillInterval)
        {
            return strategy.PathFilling(layer, fillInterval);
        }
    }
}
